package NumTheory;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class NumTheoryTest {

    private static NumTheory numTheory = new NumTheory();

    public static void main(String[] args) {

        NumTheoryTest numTheoryTest = new NumTheoryTest();
        numTheoryTest.eratosthenesTest();
        numTheoryTest.euclidTest();
        numTheoryTest.exEuclidTest();
        numTheoryTest.fastPowTest();
        numTheoryTest.crtTest();
        numTheoryTest.MRtestTest();
    }

    void eratosthenesTest() {
        BigInteger[] testInput1 = new BigInteger[]{BigInteger.valueOf(100), BigInteger.valueOf(200)};
        String[] testInput2 = new String[]{"[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]",
                "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]"};
        boolean flag = true;
        for (int i = 0; i < testInput1.length; i++) {
            if (!Arrays.toString(numTheory.eratosthenes(testInput1[i])).equals(testInput2[i])) {
                flag = false;
            }
        }
        if (flag) {
            System.out.println("eratosthenesTest：测试通过");
        } else {
            System.out.println("eratosthenesTest：测试不通过");
        }
    }

    void euclidTest() {
        BigInteger euclid = numTheory.euclid(BigInteger.valueOf(710), BigInteger.valueOf(310));
        boolean flag = euclid.compareTo(BigInteger.valueOf(10)) == 0;
        if (flag) {
            System.out.println("euclidTest：测试通过");
        } else {
            System.out.println("euclidTest：测试不通过");
        }
    }

    void exEuclidTest() {
        BigInteger[][] testData = new BigInteger[3][5];
        testData[0][0] = new BigInteger("31");
        testData[0][1] = new BigInteger("13");
        testData[0][2] = new BigInteger("-5");
        testData[0][3] = new BigInteger("12");
        testData[0][4] = new BigInteger("1");

        testData[1][0] = new BigInteger("2461502723515673086658704256944912426065172925575");
        testData[1][1] = new BigInteger("1720876577542770214811199308823476528929542231719");
        testData[1][2] = new BigInteger("-279503883787274514253902210297369853780943628056");
        testData[1][3] = new BigInteger("399795999407450264570090854758429065117844005679");
        testData[1][4] = new BigInteger("1");

        testData[2][0] = new BigInteger("13709616469144948883512229123502305176385931810284088906755090238431898972708904439178898468021710798401875986657125211084472621499595371254346390738382042");
        testData[2][1] = new BigInteger("19235039994987625167590963480899777255933775238312044097122773255647530276806317636026727679800825370459321617724871515442147432420951257037823141069640181");
        testData[2][2] = new BigInteger("-1076045803680437575165069317517720056816012968550552297497847522201869587140865136718292159497811949579872126471694232065112371318866682108000433819750738");
        testData[2][3] = new BigInteger("766942791672689226450200919445856853258490754050379704483194087100115700225755919066211027540484178869823084929299459228617007521725575705884841982026337");
        testData[2][4] = new BigInteger("1");

        boolean flag = true;
        for (int i = 0; i < testData.length; i++) {
            BigInteger[] exEuclid = numTheory.exEuclid(testData[i][0], testData[i][1]);
            if (exEuclid[0].compareTo(testData[i][4]) != 0 || exEuclid[1].compareTo(testData[i][2]) != 0 ||
                    exEuclid[2].compareTo(testData[i][3]) != 0) {
                flag = false;
            }
        }

        if (flag) {
            System.out.println("exEuclidTest：测试通过");
        } else {
            System.out.println("exEuclidTest：测试不通过");
        }
    }

    void fastPowTest() {
        BigInteger[][] testData = new BigInteger[2][4];
        testData[0][0] = new BigInteger("5");
        testData[0][1] = new BigInteger("10003");
        testData[0][2] = new BigInteger("31");
        testData[0][3] = new BigInteger("5");

        testData[1][0] = new BigInteger("1494462659429290047815067355171411187560751791530");
        testData[1][1] = new BigInteger("65537");
        testData[1][2] = new BigInteger("2268838711304724304304396119509416774597723292474");
        testData[1][3] = new BigInteger("2099538163720891467842744895846522520832379454230");

        boolean flag = true;
        for (int i = 0; i < testData.length; i++) {
            if (testData[i][3].compareTo(numTheory.fastPow(testData[i][0], testData[i][1], testData[i][2])) != 0) {
                flag = false;
            }
        }
        if (flag) {
            System.out.println("fastPowTest：测试通过");
        } else {
            System.out.println("fastPowTest：测试不通过");
        }
    }

    void crtTest() {
        boolean flag = true;

        if (numTheory.crt(new BigInteger[]{BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO},
                new BigInteger[]{BigInteger.valueOf(23), BigInteger.valueOf(28), BigInteger.valueOf(33)},
                3).compareTo(BigInteger.ZERO) != 0) {
            flag = false;
        }

        if (numTheory.crt(new BigInteger[]{BigInteger.valueOf(5), BigInteger.valueOf(20), BigInteger.valueOf(34)},
                new BigInteger[]{BigInteger.valueOf(23), BigInteger.valueOf(28), BigInteger.valueOf(33)},
                3).compareTo(BigInteger.valueOf(19900)) != 0) {
            flag = false;
        }

        if (numTheory.crt(new BigInteger[]{BigInteger.valueOf(283), BigInteger.valueOf(102), BigInteger.valueOf(23)},
                new BigInteger[]{BigInteger.valueOf(23), BigInteger.valueOf(28), BigInteger.valueOf(33)},
                3).compareTo(BigInteger.valueOf(9230)) != 0) {
            flag = false;
        }

        if (flag) {
            System.out.println("crtTest：测试通过");
        } else {
            System.out.println("crtTest：测试不通过");
        }
    }

    void MRtestTest() {

        Map<BigInteger, Boolean> testData = new HashMap<>();
        testData.put(BigInteger.valueOf(1000023), Boolean.FALSE);
        testData.put(BigInteger.valueOf(1000033), Boolean.TRUE);
        testData.put(BigInteger.valueOf(100160063), Boolean.FALSE);
        testData.put(BigInteger.valueOf(1500450271), Boolean.TRUE);

        boolean flag = true;

        for (BigInteger bigInteger : testData.keySet()) {
            if (testData.get(bigInteger) != numTheory.MRtest(bigInteger)) {
                flag = false;
            }
        }

        if (flag) {
            System.out.println("MRtestTest：测试通过");
        } else {
            System.out.println("MRtestTest：测试不通过");
        }
    }

}
